home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
drdobbs
/
1991
/
03
/
386bsd.mar
next >
Wrap
Text File
|
1991-02-15
|
36KB
|
1,218 lines
_PORTING UNIX TO THE 386: THE STANDALONE SYSTEM_
by William Frederick Jolitz and Lynne Greer Jolitz
[LISTING ONE]
# hi.s: Simplest protected mode program providing some kind of output.
.text
start: movl $0x0e690e48, 0x0b8800 # put "hi" mid screen on display
hlt
[LISTING TWO]
# hello.s: Minimal test of GNU GAS assembler, handles CGA & strings.
.text
start:
movl $0xA0000,%esp
pushl $str
call _puts
pop %eax
hlt
str: .asciz "\n\rHello world from GAS\r\n"
_puts:
push %ebx
movl 8(%esp),%ebx
1: cmpb $0,(%ebx) # until we see a null
je 2f
movzbl (%ebx),%eax
pushl %eax
call _putchar # put out characters
popl %eax
incl %ebx
jmp 1b
2: popl %ebx
ret
crtat: .long 0xb8000 # address of CGA video RAM
row: .long 0
_putchar:
movzbl 4(%esp),%eax
push %ebx
push %ecx
movl crtat,%ebx
cmpl $0xb8000+80*25*2,%ebx # continous output off screen edge & bot
jl 1f
movl $0,row
movl $0xb8000+80*(25-1)*2,%ebx
1: cmpb $0xd,%al # cr
jne 1f
movl $80,%ecx # clear rest of line
subl row,%ecx
movl %ebx,%edi
movw $0xfff,%ax
cld
rep
stosw
subl row,%ebx
subl row,%ebx
movl $0,row
jmp 9f
1: cmpb $0xa,%al # nl
jne 2f
cmpl $0xb8000+80*(25-1)*2,%ebx # scroll?
jl 1f
movl $0xb8000,%edi # scroll page
movl $0xb8000+80*2,%esi
movl $80*(25-1),%ecx
cld
rep
movsw
movl $80,%ecx # clear new bottom line
movl $0xb8000+80*(25-1)*2,%edi
movw $0,%ax
rep
stosw
sub $80*2,%ebx # position cursor before lf
1: add $80*2,%ebx
jmp 9f
2: orw $0x0e00,%ax # attribute
movw %ax,(%ebx)
addl $2,%ebx
incl row
9: movl %ebx,crtat
pop %ecx
pop %ebx
ret
[LISTING THREE]
/* [Excerpted from srt.s] */
...
entry: .globl entry
jmp 1f
.space 0x500 /* skip over BIOS data area */
1: cli /* no interrupts yet */
movl $0xA0000,%esp
movl %esp,%edx
movl $_edata,%eax
subl %eax,%edx /* clear stack and heap store */
pushl %edx
pushl %eax
call _bzero
popl %eax
popl %eax
call _main
...
/* hello.c */
main() { printf("Hello, world!\n"); }
[LISTING FOUR]
/* kbd.c: Copyright (c) 1989, 1990 William Jolitz. All rights reserved.
* Written by William Jolitz 9/89
* Redistribution and use in source and binary forms are freely permitted
* provided that the above copyright notice and attribution and date of work
* and this paragraph are duplicated in all such forms.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* Standalone driver for IBM PC keyboards.
*/
#define L 0x001 /* locking function */
#define SHF 0x002 /* keyboard shift */
#define ALT 0x004 /* alternate shift -- alternate chars */
#define NUM 0x008 /* numeric shift cursors vs. numeric */
#define CTL 0x010 /* control shift -- allows ctl function */
#define CPS 0x020 /* caps shift -- swaps case of letter */
#define ASCII 0x040 /* ascii code for this key */
#define STP 0x080 /* stop output */
#define BREAK 0x100 /* key breaking contact */
typedef unsigned char u_char;
u_char inb();
u_char action[] = {
0, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 0- 7 */
ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 8-15 */
ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 16-23 */
ASCII, ASCII, ASCII, ASCII, ASCII, CTL, ASCII, ASCII, /* scan 24-31 */
ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 32-39 */
ASCII, ASCII, SHF , ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 40-47 */
ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, SHF, ASCII, /* scan 48-55 */
ALT, ASCII, CPS|L, 0, 0, ASCII, 0, 0, /* scan 56-63 */
0, 0, 0, 0, 0, NUM|L, STP|L, ASCII, /* scan 64-71 */
ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, ASCII, /* scan 72-79 */
ASCII, ASCII, ASCII, ASCII, 0, 0, 0, 0, /* scan 80-87 */
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ;
u_char unshift[] = { /* no shift */
0, 033 , '1' , '2' , '3' , '4' , '5' , '6' , /* scan 0- 7 */
'7' , '8' , '9' , '0' , '-' , '=' , 0177 ,'\t' , /* scan 8-15 */
'q' , 'w' , 'e' , 'r' , 't' , 'y' , 'u' , 'i' , /* scan 16-23 */
'o' , 'p' , '[' , ']' , '\r' , CTL , 'a' , 's' , /* scan 24-31 */
'd' , 'f' , 'g' , 'h' , 'j' , 'k' , 'l' , ';' , /* scan 32-39 */
'\'' , '`' , SHF , '\\' , 'z' , 'x' , 'c' , 'v' , /* scan 40-47 */
'b' , 'n' , 'm' , ',' , '.' , '/' , SHF , '*', /* scan 48-55 */
ALT , ' ' , CPS|L, 0, 0, ' ' , 0, 0, /* scan 56-63 */
0, 0, 0, 0, 0, NUM|L, STP|L, '7', /* scan 64-71 */
'8', '9', '-', '4', '5', '6', '+', '1', /* scan 72-79 */
'2', '3', '0', '.', 0, 0, 0, 0, /* scan 80-87 */
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ;
u_char shift[] = { /* shift shift */
0, 033 , '!' , '@' , '#' , '$' , '%' , '^' , /* scan 0- 7 */
'&' , '*' , '(' , ')' , '_' , '+' , 0177 ,'\t' , /* scan 8-15 */
'Q' , 'W' , 'E' , 'R' , 'T' , 'Y' , 'U' , 'I' , /* scan 16-23 */
'O' , 'P' , '[' , ']' , '\r' , CTL , 'A' , 'S' , /* scan 24-31 */
'D' , 'F' , 'G' , 'H' , 'J' , 'K' , 'L' , ':' , /* scan 32-39 */
'"' , '~' , SHF , '|' , 'Z' , 'X' , 'C' , 'V' , /* scan 40-47 */
'B' , 'N' , 'M' , '<' , '>' , '?' , SHF , '*', /* scan 48-55 */
ALT , ' ' , CPS|L, 0, 0, ' ' , 0, 0, /* scan 56-63 */
0, 0, 0, 0, 0, NUM|L, STP|L, '7', /* scan 64-71 */
'8', '9', '-', '4', '5', '6', '+', '1', /* scan 72-79 */
'2', '3', '0', '.', 0, 0, 0, 0, /* scan 80-87 */
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ;
u_char ctl[] = { /* CTL shift */
0, 033 , '!' , 000 , '#' , '$' , '%' , 036 , /* scan 0- 7 */
'&' , '*' , '(' , ')' , 037 , '+' , 034 ,'\177', /* scan 8-15 */
021 , 027 , 005 , 022 , 024 , 031 , 025 , 011 , /* scan 16-23 */
017 , 020 , 033 , 035 , '\r' , CTL , 001 , 013 , /* scan 24-31 */
004 , 006 , 007 , 010 , 012 , 013 , 014 , ';' , /* scan 32-39 */
'\'' , '`' , SHF , 034 , 032 , 030 , 003 , 026 , /* scan 40-47 */
002 , 016 , 015 , '<' , '>' , '?' , SHF , '*', /* scan 48-55 */
ALT , ' ' , CPS|L, 0, 0, ' ' , 0, 0, /* scan 56-63 */
CPS|L, 0, 0, 0, 0, 0, 0, 0, /* scan 64-71 */
0, 0, 0, 0, 0, 0, 0, 0, /* scan 72-79 */
0, 0, 0, 0, 0, 0, 0, 0, /* scan 80-87 */
0, 0, 033, '7' , '4' , '1' , 0, NUM|L, /* scan 88-95 */
'8' , '5' , '2' , 0, STP|L, '9' , '6' , '3' , /*scan 96-103*/
'.' , 0, '*' , '-' , '+' , 0, 0, 0, /*scan 104-111*/
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, } ;
#define KBSTATP 0x64 /* kbd status port */
#define KBS_RDY 0x02 /* kbd char ready */
#define KBDATAP 0x60 /* kbd data port */
#define KBSTATUSPORT 0x61 /* kbd status */
#define KBD_BRK 0x80 /* key is breaking contact, not making contact */
#define KBD_KEY(s) ((s) & 0x7f) /* key that has changed */
/* Return an ASCII character from the keyboard. */
u_char kbd() {
u_char dt, act;
static u_char odt, shfts, ctls, alts, caps, num, stp;
do {
do {
while (inb(KBSTATP)&KBS_RDY) ;
dt = inb(KBDATAP);
} while (dt == odt);
odt = dt;
dt = KBD_KEY(dt);
act = action[dt];
if (odt & KBD_BRK) act |= BREAK;
/* kinds of shift keys */
if (act&SHF) actl (act, &shfts);
if (act&ALT) actl (act, &alts);
if (act&NUM) actl (act, &num);
if (act&CTL) actl (act, &ctls);
if (act&CPS) actl (act, &caps);
if (act&STP) actl (act, &stp);
if (act&(ASCII|BREAK) == ASCII) {
u_char chr;
if (shfts)
chr = shift[dt] ;
else {
if (ctls) chr = ctl[dt] ;
else chr = unshift[dt] ;
}
if (caps && (chr >= 'a' && chr <= 'z'))
chr -= 'a' - 'A' ;
return(chr);
}
} while (1);
}
/* Handle shift key actions */
actl(act, v, brk) char *v; {
/* are we locking ... */
if (act&L) {
if((act&BREAK) == 0) *v ^= 1;
/* ... or single - action ? */
} else
if(act&BREAK) *v = 0; else *v = 1;
}
[LISTING FIVE]
/* cga.c: Copyright (c) 1989, 1990 William Jolitz. All rights reserved.
* Written by William Jolitz 9/89
* Redistribution and use in source and binary forms are freely permitted
* provided that the above copyright notice and attribution and date of work
* and this paragraph are duplicated in all such forms.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* Standalone driver for IBM PC Displays like CGA.
*/
typedef unsigned short u_short;
typedef unsigned char u_char;
#define CRT_TXTADDR Crtat
#define COL 80
#define ROW 25
#define CHR 2
u_short *Crtat = ((u_short *)0xb8000); /* 0xb0000 for monochrome */
u_short *crtat;
u_char color = 0xe ;
int row;
sput(c) u_char c; {
if (crtat == 0) {
crtat = CRT_TXTADDR; bzero (crtat,COL*ROW*CHR);
}
if (crtat >= (CRT_TXTADDR+COL*ROW*CHR)) {
crtat = CRT_TXTADDR+COL*(ROW-1); row = 0;
}
switch(c) {
case '\t':
do {
*crtat++ = (color<<8)| ' '; row++ ;
} while (row %8);
break;
case '\010':
crtat--; row--;
break;
case '\r':
bzero (crtat,(COL-row)*CHR) ; crtat -= row ; row = 0;
break;
case '\n':
if (crtat >= CRT_TXTADDR+COL*(ROW-1)) { /* scroll */
bcopy(CRT_TXTADDR+COL, CRT_TXTADDR,COL*(ROW-1)*CHR);
bzero (CRT_TXTADDR+COL*(ROW-1),COL*CHR) ;
crtat -= COL ;
}
crtat += COL ;
break;
default:
*crtat++ = (color<<8)| c; row++ ;
break ;
}
}
[LISTING SIX]
/* [excerpted from i386.c] */
...
/* Descriptor Tables */
/* Global Descriptor Table */
#define GNULL_SEL 0 /* Null Descriptor - obligatory */
#define GCODE_SEL 1 /* Kernel Code Descriptor */
#define GDATA_SEL 2 /* Kernel Data Descriptor */
#define GLDT_SEL 3 /* LDT - eventually one per process */
#define GTGATE_SEL 4 /* Process task switch gate */
#define GPANIC_SEL 5 /* Task state to consider panic from */
#define GPROC0_SEL 6 /* Task state process slot zero and up */
union descriptor gdt[GPROC0_SEL+NPROC];
/* interrupt descriptor table */
struct gate_descriptor idt[NEXECPT+NINTR];
/* local descriptor table */
#define LSYS5CALLS_SEL 0 /* SVID/BCS 386 system call gate */
#define LSYS5SIGR_SEL 1 /* SVID/BCS 386 sigreturn() */
#define LBSDCALLS_SEL 2 /* BSD experimental system calls */
#define LUCODE_SEL 3 /* user process code descriptor */
#define LUDATA_SEL 4 /* user process data descriptor */
union descriptor ldt[LUDATA_SEL+1];
/* Task State Structures (TSS) for hardware context switch */
struct i386tss tss[NPROC], ptss;
/* software prototypes -- in more palitable form */
struct soft_segment_descriptor gdt_segs[GPROC0_SEL+NPROC] = {
/* Null Descriptor */
{ 0x0, /* segment base address */
0x0, /* length - all address space */
0, /* segment type */
0, /* segment descriptor priority level */
0, /* segment descriptor present */
0,0,
0, /* default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* Code Descriptor for kernel */
{ 0x0, /* segment base address */
0xfffff, /* length - all address space */
SDT_MEMERA, /* segment type */
0, /* segment descriptor priority level */
1, /* segment descriptor present */
0,0,
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* Data Descriptor for kernel */
{ 0x0, /* segment base address */
0xfffff, /* length - all address space */
SDT_MEMRWA, /* segment type */
0, /* segment descriptor priority level */
1, /* segment descriptor present */
0,0,
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* LDT Descriptor */
{ (int) ldt, /* segment base address */
sizeof(ldt)-1, /* length - all address space */
SDT_SYSLDT, /* segment type */
0, /* segment descriptor priority level */
1, /* segment descriptor present */
0,0,
0, /* unused - default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* Null Descriptor - Placeholder */
{ 0x0, /* segment base address */
0x0, /* length - all address space */
0, /* segment type */
0, /* segment descriptor priority level */
0, /* segment descriptor present */
0,0,
0, /* default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* Panic Tss Descriptor */
{ (int) &ptss, /* segment base address */
sizeof(tss)-1, /* length - all address space */
SDT_SYS386TSS, /* segment type */
0, /* segment descriptor priority level */
1, /* segment descriptor present */
0,0,
0, /* unused - default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* Process 0 Tss Descriptor */
{ (int) &tss[0], /* segment base address */
sizeof(tss)-1, /* length - all address space */
SDT_SYS386TSS, /* segment type */
0, /* segment descriptor priority level */
1, /* segment descriptor present */
0,0,
0, /* unused - default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ } };
struct soft_segment_descriptor ldt_segs[] = {
/* Null Descriptor - overwritten by call gate */
{ 0x0, /* segment base address */
0x0, /* length - all address space */
0, /* segment type */
0, /* segment descriptor priority level */
0, /* segment descriptor present */
0,0,
0, /* default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* Null Descriptor - overwritten by call gate */
{ 0x0, /* segment base address */
0x0, /* length - all address space */
0, /* segment type */
0, /* segment descriptor priority level */
0, /* segment descriptor present */
0,0,
0, /* default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* Null Descriptor - overwritten by call gate */
{ 0x0, /* segment base address */
0x0, /* length - all address space */
0, /* segment type */
0, /* segment descriptor priority level */
0, /* segment descriptor present */
0,0,
0, /* default 32 vs 16 bit size */
0 /* limit granularity (byte/page units)*/ },
/* Code Descriptor for user */
{ 0x0, /* segment base address */
0xfffff, /* length - all address space */
SDT_MEMERA, /* segment type */
SEL_UPL, /* segment descriptor priority level */
1, /* segment descriptor present */
0,0,
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ },
/* Data Descriptor for user */
{ 0x0, /* segment base address */
0xfffff, /* length - all address space */
SDT_MEMRWA, /* segment type */
SEL_UPL, /* segment descriptor priority level */
1, /* segment descriptor present */
0,0,
1, /* default 32 vs 16 bit size */
1 /* limit granularity (byte/page units)*/ } };
...
extern ssdtosd(), lgdt(), lidt(), lldt(), usercode(), touser();
init386() {
...
/* make gdt memory segments */
for (x=0; x < sizeof gdt / sizeof gdt[0] ; x++)
ssdtosd(gdt_segs+x, gdt+x);
printf("lgdt\n"); getchar();
lgdt(gdt, sizeof(gdt)-1);
/* make ldt memory segments */
for (x=0; x < sizeof ldt / sizeof ldt[0] ; x++)
ssdtosd(ldt_segs+x, ldt+x);
/* make a call gate to reenter kernel with */
setgate(&ldt[LSYS5CALLS_SEL].gd, &IDTVEC(syscall), SDT_SYS386CGT,
SEL_UPL);
printf("lldt\n"); getchar();
lldt(GSEL(GLDT_SEL, SEL_KPL));
...
/* [excerpted from srt.s] */
...
/* lgdt(*gdt, ngdt) */
.globl _lgdt
gdesc: .word 0
.long 0
_lgdt:
movl 4(%esp),%eax
movl %eax,gdesc+2
movl 8(%esp),%eax
movw %ax,gdesc
lgdt gdesc
jmp 1f /* flush instruction prefetch q */
nop
1: movw $0x10,%ax /* reload other "well known" descriptors */
movw %ax,%ds
movw %ax,%es
movw %ax,%ss
movl 0(%esp),%eax
pushl %eax
movl $8,4(%esp) /* including the ever popular CS */
lret
...
/* lldt(sel) */
.globl _lldt
_lldt:
lldt 4(%esp)
ret
...
[LISTING SEVEN]
/* segments.h: Copyright (c) 1989, 1990 William Jolitz. All rights reserved.
* Written by William Jolitz 6/20/1989
* Redistribution and use in source and binary forms are freely permitted
* provided that the above copyright notice and attribution and date of work
* and this paragraph are duplicated in all such forms.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* 386 Segmentation Data Structures and definitions
*/
/* Selectors */
#define ISPL(s) ((s)&3) /* what is the priority level of a selector */
#define SEL_KPL 0 /* kernel priority level */
#define SEL_UPL 3 /* user priority level */
#define ISLDT(s) ((s)&SEL_LDT) /* is it local or global */
#define SEL_LDT 4 /* local descriptor table */
#define IDXSEL(s) (((s)>>3) & 0x1fff) /* index of selector */
#define LSEL(s,r) (((s)<<3) | SEL_LDT | r) /* a local selector */
#define GSEL(s,r) (((s)<<3) | r) /* a global selector */
/* Memory and System segment descriptors */
struct segment_descriptor {
unsigned sd_lolimit:16 ; /* segment extent (lsb) */
unsigned sd_lobase:24 ; /* segment base address (lsb) */
unsigned sd_type:5 ; /* segment type */
unsigned sd_dpl:2 ; /* segment descriptor priority level */
unsigned sd_p:1 ; /* segment descriptor present */
unsigned sd_hilimit:4 ; /* segment extent (msb) */
unsigned sd_xx:2 ; /* unused */
unsigned sd_def32:1 ; /* default 32 vs 16 bit size */
unsigned sd_gran:1 ; /* limit granularity (byte/page units)*/
unsigned sd_hibase:8 ; /* segment base address (msb) */
} ;
/* Gate descriptors (e.g. indirect descriptors) */
struct gate_descriptor {
unsigned gd_looffset:16 ; /* gate offset (lsb) */
unsigned gd_selector:16 ; /* gate segment selector */
unsigned gd_stkcpy:5 ; /* number of stack wds to cpy */
unsigned gd_xx:3 ; /* unused */
unsigned gd_type:5 ; /* segment type */
unsigned gd_dpl:2 ; /* segment descriptor priority level */
unsigned gd_p:1 ; /* segment descriptor present */
unsigned gd_hioffset:16 ; /* gate offset (msb) */
} ;
/* Generic descriptor */
union descriptor {
struct segment_descriptor sd;
struct gate_descriptor gd;
};
#define d_type gd.gd_type
/* system segments and gate types */
#define SDT_SYSNULL 0 /* system null */
#define SDT_SYS286TSS 1 /* system 286 TSS available */
#define SDT_SYSLDT 2 /* system local descriptor table */
#define SDT_SYS286BSY 3 /* system 286 TSS busy */
#define SDT_SYS286CGT 4 /* system 286 call gate */
#define SDT_SYSTASKGT 5 /* system task gate */
#define SDT_SYS286IGT 6 /* system 286 interrupt gate */
#define SDT_SYS286TGT 7 /* system 286 trap gate */
#define SDT_SYSNULL2 8 /* system null again */
#define SDT_SYS386TSS 9 /* system 386 TSS available */
#define SDT_SYSNULL3 10 /* system null again */
#define SDT_SYS386BSY 11 /* system 386 TSS busy */
#define SDT_SYS386CGT 12 /* system 386 call gate */
#define SDT_SYSNULL4 13 /* system null again */
#define SDT_SYS386IGT 14 /* system 386 interrupt gate */
#define SDT_SYS386TGT 15 /* system 386 trap gate */
/* memory segment types */
#define SDT_MEMRO 16 /* memory read only */
#define SDT_MEMROA 17 /* memory read only accessed */
#define SDT_MEMRW 18 /* memory read write */
#define SDT_MEMRWA 19 /* memory read write accessed */
#define SDT_MEMROD 20 /* memory read only expand dwn limit */
#define SDT_MEMRODA 21 /* memory read only expand dwn limit accessed */
#define SDT_MEMRWD 22 /* memory read write expand dwn limit */
#define SDT_MEMRWDA 23 /* memory r/w expand dwn limit acessed */
#define SDT_MEME 24 /* memory execute only */
#define SDT_MEMEA 25 /* memory execute only accessed */
#define SDT_MEMER 26 /* memory execute read */
#define SDT_MEMERA 27 /* memory execute read accessed */
#define SDT_MEMEC 28 /* memory execute only conforming */
#define SDT_MEMEAC 29 /* memory execute only accessed conforming */
#define SDT_MEMERC 30 /* memory execute read conforming */
#define SDT_MEMERAC 31 /* memory execute read accessed conforming */
/* is memory segment descriptor pointer ? */
#define ISMEMSDP(s) ((s->d_type) >= SDT_MEMRO && (s->d_type) <= SDT_MEMERAC)
/* is 286 gate descriptor pointer ? */
#define IS286GDP(s) (((s->d_type) >= SDT_SYS286CGT \
&& (s->d_type) < SDT_SYS286TGT))
/* is 386 gate descriptor pointer ? */
#define IS386GDP(s) (((s->d_type) >= SDT_SYS386CGT \
&& (s->d_type) < SDT_SYS386TGT))
/* is gate descriptor pointer ? */
#define ISGDP(s) (IS286GDP(s) || IS386GDP(s))
/* is segment descriptor pointer ? */
#define ISSDP(s) (ISMEMSDP(s) || !ISGDP(s))
/* is system segment descriptor pointer ? */
#define ISSYSSDP(s) (!ISMEMSDP(s) && !ISGDP(s))
/* Software definitions are in this convenient format; translated into
* inconvenient segment descriptors when needed to be used by 386 hardware */
struct soft_segment_descriptor {
unsigned ssd_base ; /* segment base address */
unsigned ssd_limit ; /* segment extent */
unsigned ssd_type:5 ; /* segment type */
unsigned ssd_dpl:2 ; /* segment descriptor priority level */
unsigned ssd_p:1 ; /* segment descriptor present */
unsigned ssd_xx:4 ; /* unused */
unsigned ssd_xx1:2 ; /* unused */
unsigned ssd_def32:1 ; /* default 32 vs 16 bit size */
unsigned ssd_gran:1 ; /* limit granularity (byte/page units)*/
};
extern ssdtosd() ; /* to decode a ssd */
extern sdtossd() ; /* to encode a sd */
/* region descriptors, used to load gdt/idt tables before segments yet exist */
struct region_descriptor {
unsigned rd_limit:16 ; /* segment extent */
char *rd_base; /* base address */
};
/* Segment Protection Exception code bits */
#define SEGEX_EXT 0x01 /* recursive or externally induced */
#define SEGEX_IDT 0x02 /* interrupt descriptor table */
#define SEGEX_TI 0x04 /* local descriptor table */
/* other bits are affected descriptor index */
#define SEGEX_IDX(s) ((s)>>3)&0x1fff)
[LISTING EIGHT]
/* [excerpted from i386.c] */
...
/* Assemble a gate descriptor */
setgate(gp, func, typ, dpl) char *func; struct gate_descriptor *gp; {
gp->gd_looffset = (int)func;
gp->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
gp->gd_stkcpy = 0;
gp->gd_xx = 0;
gp->gd_type = typ;
gp->gd_dpl = dpl;
gp->gd_p = 1; /* definitely present */
gp->gd_hioffset = ((int)func)>>16 ;
}
/* ASM entry points to exception/trap/interrupt entry stub code. */
#define IDTVEC(name) X##name
extern
IDTVEC(div), IDTVEC(dbg), IDTVEC(nmi), IDTVEC(bpt), IDTVEC(ofl),
IDTVEC(bnd), IDTVEC(ill), IDTVEC(dna), IDTVEC(dble), IDTVEC(fpusegm),
IDTVEC(tss), IDTVEC(missing), IDTVEC(stk), IDTVEC(prot), IDTVEC(page),
IDTVEC(rsvd), IDTVEC(fpu), IDTVEC(rsvd0), IDTVEC(rsvd1), IDTVEC(rsvd2),
IDTVEC(rsvd3), IDTVEC(rsvd4), IDTVEC(rsvd5), IDTVEC(rsvd6),
IDTVEC(rsvd7), IDTVEC(rsvd8), IDTVEC(rsvd9), IDTVEC(rsvd10),
IDTVEC(rsvd11), IDTVEC(rsvd12), IDTVEC(rsvd13), IDTVEC(rsvd14),
IDTVEC(rsvd14), IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2),
IDTVEC(intr3), IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6),
IDTVEC(intr7), IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10),
IDTVEC(intr11), IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14),
IDTVEC(intr15), IDTVEC(syscall);
init386() {
...
/* exceptions */
setgate(idt+0, &IDTVEC(div), SDT_SYS386TGT, SEL_KPL);
setgate(idt+1, &IDTVEC(dbg), SDT_SYS386TGT, SEL_KPL);
setgate(idt+2, &IDTVEC(nmi), SDT_SYS386TGT, SEL_KPL);
setgate(idt+3, &IDTVEC(bpt), SDT_SYS386TGT, SEL_KPL);
setgate(idt+4, &IDTVEC(ofl), SDT_SYS386TGT, SEL_KPL);
setgate(idt+5, &IDTVEC(bnd), SDT_SYS386TGT, SEL_KPL);
setgate(idt+6, &IDTVEC(ill), SDT_SYS386TGT, SEL_KPL);
setgate(idt+7, &IDTVEC(dna), SDT_SYS386TGT, SEL_KPL);
setgate(idt+8, &IDTVEC(dble), SDT_SYS386TGT, SEL_KPL);
setgate(idt+9, &IDTVEC(fpusegm), SDT_SYS386TGT, SEL_KPL);
setgate(idt+10, &IDTVEC(tss), SDT_SYS386TGT, SEL_KPL);
setgate(idt+11, &IDTVEC(missing), SDT_SYS386TGT, SEL_KPL);
setgate(idt+12, &IDTVEC(stk), SDT_SYS386TGT, SEL_KPL);
setgate(idt+13, &IDTVEC(prot), SDT_SYS386TGT, SEL_KPL);
setgate(idt+14, &IDTVEC(page), SDT_SYS386TGT, SEL_KPL);
setgate(idt+15, &IDTVEC(rsvd), SDT_SYS386TGT, SEL_KPL);
setgate(idt+16, &IDTVEC(fpu), SDT_SYS386TGT, SEL_KPL);
setgate(idt+17, &IDTVEC(rsvd0), SDT_SYS386TGT, SEL_KPL);
setgate(idt+18, &IDTVEC(rsvd1), SDT_SYS386TGT, SEL_KPL);
setgate(idt+19, &IDTVEC(rsvd2), SDT_SYS386TGT, SEL_KPL);
setgate(idt+20, &IDTVEC(rsvd3), SDT_SYS386TGT, SEL_KPL);
setgate(idt+21, &IDTVEC(rsvd4), SDT_SYS386TGT, SEL_KPL);
setgate(idt+22, &IDTVEC(rsvd5), SDT_SYS386TGT, SEL_KPL);
setgate(idt+23, &IDTVEC(rsvd6), SDT_SYS386TGT, SEL_KPL);
setgate(idt+24, &IDTVEC(rsvd7), SDT_SYS386TGT, SEL_KPL);
setgate(idt+25, &IDTVEC(rsvd8), SDT_SYS386TGT, SEL_KPL);
setgate(idt+26, &IDTVEC(rsvd9), SDT_SYS386TGT, SEL_KPL);
setgate(idt+27, &IDTVEC(rsvd10), SDT_SYS386TGT, SEL_KPL);
setgate(idt+28, &IDTVEC(rsvd11), SDT_SYS386TGT, SEL_KPL);
setgate(idt+29, &IDTVEC(rsvd12), SDT_SYS386TGT, SEL_KPL);
setgate(idt+30, &IDTVEC(rsvd13), SDT_SYS386TGT, SEL_KPL);
setgate(idt+31, &IDTVEC(rsvd14), SDT_SYS386TGT, SEL_KPL);
/* first icu */
setgate(idt+32, &IDTVEC(intr0), SDT_SYS386IGT, SEL_KPL);
setgate(idt+33, &IDTVEC(intr1), SDT_SYS386IGT, SEL_KPL);
setgate(idt+34, &IDTVEC(intr2), SDT_SYS386IGT, SEL_KPL);
setgate(idt+35, &IDTVEC(intr3), SDT_SYS386IGT, SEL_KPL);
setgate(idt+36, &IDTVEC(intr4), SDT_SYS386IGT, SEL_KPL);
setgate(idt+37, &IDTVEC(intr5), SDT_SYS386IGT, SEL_KPL);
setgate(idt+38, &IDTVEC(intr6), SDT_SYS386IGT, SEL_KPL);
setgate(idt+39, &IDTVEC(intr7), SDT_SYS386IGT, SEL_KPL);
/* second icu */
setgate(idt+40, &IDTVEC(intr8), SDT_SYS386IGT, SEL_KPL);
setgate(idt+41, &IDTVEC(intr9), SDT_SYS386IGT, SEL_KPL);
setgate(idt+42, &IDTVEC(intr10), SDT_SYS386IGT, SEL_KPL);
setgate(idt+43, &IDTVEC(intr11), SDT_SYS386IGT, SEL_KPL);
setgate(idt+44, &IDTVEC(intr12), SDT_SYS386IGT, SEL_KPL);
setgate(idt+45, &IDTVEC(intr13), SDT_SYS386IGT, SEL_KPL);
setgate(idt+46, &IDTVEC(intr14), SDT_SYS386IGT, SEL_KPL);
setgate(idt+47, &IDTVEC(intr15), SDT_SYS386IGT, SEL_KPL);
printf("lidt\n"); getchar();
lidt(idt, sizeof(idt)-1);
...
/* [excerpted from srt.s] */
/* lidt(*idt, nidt) */
.globl _lidt
idesc: .word 0
.long 0
_lidt:
movl 4(%esp),%eax
movl %eax,idesc+2
movl 8(%esp),%eax
movw %ax,idesc
lidt idesc
ret
[LISTING NINE]
/* [excerpted from i386.c] */
...
#define NBPG 4096 /* number of bytes per page */
#define PG_V 0x00000001 /* mark this page as valid */
#define PG_UW 0x00000006 /* user and supervisor writable */
int lcr0(), lcr3();
...
init386() {
/* bag of bytes to put page table, page directory in */
static char bag[(1+1+1)*NBPG];
int *ppte, *pptd, *cr3, x;
/* make page table & directory aligned to NBPG */
ppte = (int *) (((int) bag + NBPG-1) & ~(NBPG-1));
cr3 = pptd = ppte + 1024;
/* page table directory only has lowest 4MB entry mapped */
*pptd++ = (int) ppte + (PG_V|PG_UW);
for (x = 1; x < 1024 ; x++,pptd++) *pptd = 0;
/* page table, all entrys virtual == real, user/supervisor r/w */
for (x = 0; x < 1024 ; x++,ppte++) *ppte = x*NBPG + (PG_V|PG_UW) ;
/* turn on paging */
lcr3(cr3);
printf("paging"); getchar();
lcr0(0x80000001);
...
/* [excerpted from srt.s] */
/*
* lcr3(cr3)
*/
.globl _lcr3
_lcr3:
movl 4(%esp),%eax
movl %eax,%cr3
ret
/* lcr0(cr0) */
.globl _lcr0
_lcr0:
movl 4(%esp),%eax
movl %eax,%cr0
ret
[LISTING TEN]
/* [excerpted from i386.c] */
...
init386(){
...
/* make a initial tss so 386 can get interrupt stack on syscall! */
tss[0].tss_esp0 = (int) &x - 4096;
tss[0].tss_ss0 = GSEL(GDATA_SEL, SEL_KPL) ;
tss[0].tss_cr3 = (int) cr3;
printf("ltr "); getchar();
ltr(GSEL(GPROC0_SEL, SEL_KPL));
printf("resume() "); getchar();
/* set busy type to avail */
gdt[GPROC0_SEL].sd.sd_type = SDT_SYS386TSS;
/* jump to self to fill out tss, like BSD resume() */
jmptss(GSEL(GPROC0_SEL, SEL_KPL));
...
# excerpted from srt.s
...
/* jmptss(sel)-- Jump to TSS so that we can load/unload context */
.globl _jmptss /* similar to BSD swtch()/resume() */
_jmptss:
ljmp 0(%esp) /* ljmp tss */
/* saved pc points here */
ret
[LISTING ELEVEN]
/* [excerpted from i386.c] */
...
test386(){
...
/* test handling exceptions */
printf("breakpoint "); getchar();
asm (" int $3 ");
...
/* Trap exception processing code */
trap(es, ds, edi, esi, ebp, dummy, ebx, edx, ecx, eax,
fault, ec, eip, cs, eflags, esp, ss) {
printf("pc:%x cs:%x ds:%x eflags:%x ec %x fault %x cr0 %x cr2 %x \n",
eip, cs, ds, eflags, ec, fault, rcr0(), rcr2());
printf("edi %x esi %x ebp %x ebx %x edx %x ecx %x eax %x\n",
edi, esi, ebp, ebx, edx, ecx, eax);
eip++; /* simple way to 'jump' over fault */
getchar();
}
...
# excerpted from srt.s
...
#include <machine/i386/trap.h>
#define IDTVEC(name) .align 4; .globl _X##name; _X##name:
...
/* Trap and fault vector routines */
#define TRAP(a) pushl $##a ; jmp alltraps
IDTVEC(div)
pushl $0; TRAP(T_DIVIDE)
IDTVEC(dbg)
pushl $0; TRAP(T_DEBUG)
IDTVEC(nmi)
pushl $0; TRAP(T_NMI)
IDTVEC(bpt)
pushl $0; TRAP(T_BPTFLT)
IDTVEC(ofl)
pushl $0; TRAP(T_OFLOW)
IDTVEC(bnd)
pushl $0; TRAP(T_BOUND)
IDTVEC(ill)
pushl $0; TRAP(T_PRIVINFLT)
IDTVEC(dna)
pushl $0; TRAP(T_DNA)
IDTVEC(dble)
TRAP(T_DOUBLEFLT)
IDTVEC(fpusegm)
pushl $0; TRAP(T_FPOPFLT)
IDTVEC(tss)
TRAP(T_TSSFLT)
IDTVEC(missing)
TRAP(T_SEGNPFLT)
IDTVEC(stk)
TRAP(T_STKFLT)
IDTVEC(prot)
TRAP(T_PROTFLT)
IDTVEC(page)
TRAP(T_PAGEFLT)
IDTVEC(rsvd)
pushl $0; TRAP(T_RESERVED)
IDTVEC(fpu)
pushl $0; TRAP(T_ARITHTRAP)
/* 17 - 31 reserved for future exp */
IDTVEC(rsvd0)
pushl $0; TRAP(17)
IDTVEC(rsvd1)
pushl $0; TRAP(18)
IDTVEC(rsvd2)
pushl $0; TRAP(19)
IDTVEC(rsvd3)
pushl $0; TRAP(20)
IDTVEC(rsvd4)
pushl $0; TRAP(21)
IDTVEC(rsvd5)
pushl $0; TRAP(22)
IDTVEC(rsvd6)
pushl $0; TRAP(23)
IDTVEC(rsvd7)
pushl $0; TRAP(24)
IDTVEC(rsvd8)
pushl $0; TRAP(25)
IDTVEC(rsvd9)
pushl $0; TRAP(26)
IDTVEC(rsvd10)
pushl $0; TRAP(27)
IDTVEC(rsvd11)
pushl $0; TRAP(28)
IDTVEC(rsvd12)
pushl $0; TRAP(29)
IDTVEC(rsvd13)
pushl $0; TRAP(30)
IDTVEC(rsvd14)
pushl $0; TRAP(31)
alltraps:
pushal
push %ds # save old selector's we will use
push %es
movw $0x10,%ax # load them with kernel global data sel
movw %ax,%ds
movw %ax,%es
call _trap
pop %es
pop %ds
popal
addl $8,%esp # pop type, code
iret
[LISTING TWELVE]
/* [excerpted from i386.c] */
...
init386() {
...
outb(0xf1,0); /* clear coprocessor to cover all bases */
/* initialize 8259 ICU's in preperation for device interrupts */
outb(ICU1,0x11); /* reset the unit */
outb(ICU1+1,32); /* start with idt 32 */
outb(ICU1+1,4); /* master please */
outb(ICU1+1,1);
outb(ICU1+1,0xff); /* all disabled */
outb(ICU2,0x11);
outb(ICU2+1,40); /* start with idt 40 */
outb(ICU2+1,2); /* just a slave */
outb(ICU2+1,1);
outb(ICU2+1,0xff); /* all disabled */
/* initialize 8253 timer on interrupt #0 */
outb (0x43, 0x36);
outb (0x40, 193182/60);
outb (0x40, (193182/60)/256);
}
test386(){
...
/* test interrupts for a while */
printf("inton"); getchar();
outb(ICU1+1,0); /* unmask all interrupts */
outb(ICU2+1,0);
inton();
timeout = 0x8000000;
do nothing(); while (timeout-- );
intoff();
...
# excerpted from srt.s
...
#define INTR(a) \
pushal ; \
push %ds ; \
push %es ; \
movw $0x10, %ax ; \
movw %ax, %ds ; \
movw %ax,%es ; \
pushl $##a ; \
call _intr ; \
pop %eax ; \
pop %es ; \
pop %ds ; \
popal ; \
iret
/* hardware 32 - 47 */
IDTVEC(intr0)
INTR(0)
IDTVEC(intr1)
INTR(1)
IDTVEC(intr2)
INTR(2)
IDTVEC(intr3)
INTR(3)
IDTVEC(intr4)
INTR(4)
IDTVEC(intr5)
INTR(5)
IDTVEC(intr6)
INTR(6)
IDTVEC(intr7)
INTR(7)
IDTVEC(intr8)
INTR(8)
IDTVEC(intr9)
INTR(9)
IDTVEC(intr10)
INTR(10)
IDTVEC(intr11)
INTR(11)
IDTVEC(intr12)
INTR(12)
IDTVEC(intr13)
INTR(13)
IDTVEC(intr14)
INTR(14)
IDTVEC(intr15)
INTR(15)
.globl _inton
_inton:
sti
ret
.globl _intoff
_intoff:
cli
ret
...
/* back to i386.c */
...
/* Interrupt vector processing code */
intr(ivec) {
static clk;
int omsk1, omsk2;
/* mask off interrupt being serviced, save old mask */
if (ivec > 7) {
omsk2 = inb(ICU2+1);
outb(ICU2+1, 1<<(ivec-8));
} else {
omsk1 = inb(ICU1+1);
outb(ICU1+1, 1<<ivec);
}
/* re-enable processor's interrupts, allowing others in */
inton();
/* if we are the clock, count clock tick */
if (ivec == 0) clk++;
/* if we are the keyboard, show data incoming */
else if (ivec == 1) printf("kbd data %x, clk %d\n", inb(0x60), clk);
/* otherwise print message stating source and time */
else {
printf("intr %d, clk %d \n", ivec, clk);
getchar();
}
/* turn off interrupts, re-enable old mask, do interrupt acknowledge */
intoff();
if (ivec > 7) {
outb(ICU2+1,omsk2);
outb(ICU2,0x20);
} else
outb(ICU1+1,omsk1);
outb(ICU1,0x20);
/* return to interrupt stub */
}
...
[LISTING THIRTEEN]
test386(){
...
/* transfer to user mode to test system call */
printf("touser "); getchar();
touser (LSEL(LUCODE_SEL,SEL_UPL), LSEL(LUDATA_SEL, SEL_UPL), &usercode);
...
# [excerpted from srt.s]
/* touser (cs,ds,func) */
.globl _touser
_touser:
pushal
movl %esp,_myspback
movl 32+4(%esp),%eax
movl 32+8(%esp),%edx
movl 32+12(%esp),%ecx
# build outer stack frame
pushl %edx # user ss
pushl %esp # user esp
pushl %eax # cs
pushl %ecx # ip
movw %dx,%ds
movw %dx,%es
lret # goto user!
/* code to execute in user mode */
.globl _usercode
#define LCALL(x,y) .byte 0x9a ; .long y; .word x
_usercode:
LCALL(0x7,0x0) /* would be lcall $0x7,0x0 except for assembler bug */
IDTVEC(syscall)
pushal
movw $0x10,%ax
movw %ax,%ds
movw %ax,%es
call _syscall
movl _myspback,%esp /* non-local goto touser() exit */
popal
ret
/* back to i386.c */
...
/* System call processing */
syscall() {
printf("syscall\n");
}
[LISTING FOURTEEN]
/* trap.h: i386 trap type index [as they intersect with other BSD systems] */
#define T_PRIVINFLT 1 /* privileged instruction */
#define T_BPTFLT 3 /* breakpoint instruction */
#define T_ARITHTRAP 6 /* arithmetic trap */
#define T_PROTFLT 9 /* protection fault */
#define T_PAGEFLT 12 /* page fault */
#define T_DIVIDE 18 /* integer divide fault */
#define T_NMI 19 /* non-maskable trap */
#define T_OFLOW 20 /* overflow trap */
#define T_BOUND 21 /* bound instruction fault */
#define T_DNA 22 /* device not available fault */
#define T_DOUBLEFLT 23 /* double fault */
#define T_FPOPFLT 24 /* fp coprocessor operand fetch fault */
#define T_TSSFLT 25 /* invalid tss fault */
#define T_SEGNPFLT 26 /* segment not present fault */
#define T_STKFLT 27 /* stack fault */
#define T_RESERVED 28 /* reserved fault base */
[LISTING FIFTEEN]
/* [excerpted from i386.c] */
...
test386(){
int x, *pi, timeout;
...
/* generate a page fault exception */
printf("dopagflt\n"); getchar();
pi = (int *) 0x800000; /* above 4MB */
x = *pi; /* will fault invalid read */
*pi = ++x ; /* will fault invalid write */
...